/* 
 * File:   AcptEpoll.cpp
 * Author: kisme
 * 
 * Created on 03 January 2013, 3:06 PM
 */

#include "AcptEpoll.h"

AcptEpoll::AcptEpoll() {
    this->mConf = new Conf_AcptEpoll();
}

AcptEpoll::AcptEpoll(const AcptEpoll& orig) {
}

AcptEpoll::~AcptEpoll() {
}

Conf_AcptEpoll::Conf_AcptEpoll() {
    maxEpollSize = 600;
    maxInfoSize = 1200;
    onoff = 1;
    event.events = EPOLLIN | EPOLLET;
    epollfd = epoll_create(maxEpollSize);
}

Info_Coming::Info_Coming(){
    
}

int AcptEpoll::config(const int aSockFd) {
    // main configure interface
    this->mConf->event.data.fd = aSockFd;
    return 0;
}

int AcptEpoll::ready() {
    int _result = RESULT_FAI;
    // place epoll_ctl's return num
    int _state = 0;
    this->mLogger->log_default("epoll_ctl开始执行");
    _state = epoll_ctl(this->mConf->epollfd, EPOLL_CTL_ADD,
            this->mConf->event.data.fd, &(this->mConf->event));

    if (_state < 0) {
        fprintf(stderr, "epoll Error|fd:%d Err:%s\n",
                this->mConf->event.data.fd, strerror(errno));
    } else {
        _result = RESULT_SUC;
        fprintf(stdout, "epoll Success|fd:%d, Sockfd:%d\n",
                this->mConf->epollfd, this->mConf->event.data.fd);
    }
    return _result;
}

int AcptEpoll::listen() {
    int _result = RESULT_FAI;
    struct epoll_event *_events = new epoll_event[this->mConf->maxInfoSize];
    // event amount
    int _amount = 0;
    // listening cycle..
    while (this->mConf->onoff) {
        this->mLogger->log_default(":::One Waiting ... \n");
        // listening
        _amount = epoll_wait(this->mConf->epollfd, _events, this->mConf->maxEpollSize, -1);

        if (_amount == -1) {
            fprintf(stderr, "epoll_wait error|Err:%s\n", strerror(errno));
            continue;
        }
        for (int i = 0; i < _amount; i++) {
            int _catchFd = _events[i].data.fd;
            switch (_events[i].events) {
                case EPOLLIN:
                    // an accept event, catch_fd equal serverfd
                    if (_catchFd == this->mConf->event.data.fd) {
                        fprintf(stdout, "Accept One, Server fd is:%d\n", _catchFd);
                        // coming fd
                        int _newFd;
                        // coming connect info
                        Info_Coming _info;
                        _newFd = accept(_catchFd, (struct sockaddr*)&(_info.client_addr), &(_info.client_len));

                        if (_newFd < 0) {
                            fprintf(stderr, "_newFd < 0|fd=%d Err:%s \n ",
                                    _newFd, strerror(errno));
                        } else {
                            // use for ctl client.
                            struct epoll_event _event;

                            fprintf(stdout, "A New Connect,IP:%s:%d fd:%d\n", inet_ntoa(_info.client_addr.sin_addr), ntohs(_info.client_addr.sin_port), _newFd);

                            setNonblock(_newFd);
                            // deploy the new fd's epoll attribute
                            _event.events = EPOLLIN | EPOLLET;
                            _event.data.fd = _newFd;

                            if (epoll_ctl(this->mConf->epollfd, EPOLL_CTL_ADD, _newFd, &_event) < 0) {
                                fprintf(stderr, "ctl client newfd error: fd=%d :::Errno:%s \n ", _newFd, strerror(errno));
                            }
                        }
                    }// a io data receive
                    else {
                        fprintf(stdout, "Receive One fd=%d\n", _catchFd);
                        char _buf[1024 + 1];
                        int _len;
                        /* 开始处理每个新连接上的数据收发 */
                        bzero(_buf, 1024 + 1);
                        do {
                            /* 接收客户端的消息 */
                            _len = recv(_catchFd, _buf, 1024, 0);

                            printf("_len=%d Recving.. errno %s %d\n", _len, strerror(errno), errno);

                        } while (errno != EAGAIN);

                        if ((_len > 0 && errno == EAGAIN) || (_len < 0 && errno == EAGAIN)) {
                            printf("errno %s %d\n", strerror(errno), errno);
                            printf("fd=%d 接收消息成功:\n%s\n共%d个字节的数据\n",
                                    _catchFd, _buf, _len);
                            int t_len = write(_catchFd, _buf, strlen(_buf));
                        } else {
                            if (_len < 0 || _len == 0)
                                printf
                                    ("消息接收失败！len= %d,错误代码是%d，错误信息是'%s'\n", _len,
                                    errno, strerror(errno));
                        }
                    }
                    break;
                case EPOLLOUT:
                    printf("一次OUT！errno代码是%d，strerrno是'%s'\n", errno, strerror(errno));
                    break;
            }
        }
    }
    return _result;
}

int AcptEpoll::turn(const int aOnOff) {
    this->mConf->onoff = aOnOff;
    return 0;
}
